﻿using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using AutoLoL.Entities;
using AutoLoL.Logic.Parsers;
using AutoLoL.Logic.Utils;
using AutoLoL.Shared;

namespace AutoLoL.Logic.Repositories
{
    public class LocalItemRepository : IItemRepository
    {
        private ReadOnlyCollection<Item> _items;

        public LocalItemRepository()
        {
        }

        public Item GetByItemId(int itemId)
        {
            if (itemId > 0)
            {
                return GetAll().Where(c => c.ItemId == itemId).SingleOrDefault();
            }

            return null;
        }

        public ReadOnlyCollection<Item> GetAll()
        {
            if (_items != null)
            {
                return _items;
            }
            List<Item> items = new List<Item>();

            Dictionary<Item, int[]> builtFromMapping = new Dictionary<Item, int[]>();
            Dictionary<Item, int[]> buildsIntoMapping = new Dictionary<Item, int[]>();

            if (File.Exists(Constants.ITEMS_XML_FILE))
            {
                XDocument itemsDoc = XDocument.Load(Constants.ITEMS_XML_FILE);
                foreach (XElement itemElement in itemsDoc.Root.Elements("item"))
                {
                    int id = int.Parse(itemElement.Element("id").Value);
                    string name = itemElement.Element("name").Value;
                    string icon = itemElement.Element("icon").Value;
                    string description = itemElement.Element("description").Value;
                    int price = int.Parse(itemElement.Element("price").Value);

                    string iconPath = Path.Combine(Constants.ITEMS_DIRECTORY, icon);

                    Item item = new Item();
                    item.ItemId = id;
                    item.Name = name;
                    item.IconBitmapImage = ImageParser.FileToBitmapImage(iconPath);
                    item.Description = description;
                    item.Price = price;

                    #region Built From
                    List<int> builtFromList = new List<int>();
                    foreach (XElement builtFromElement in itemElement.Element("built_from").Elements("item"))
                    {
                        int builtFromid = int.Parse(builtFromElement.Attribute("id").Value);
                        if (!builtFromList.Contains(builtFromid))
                        {
                            builtFromList.Add(builtFromid);
                        }
                    }

                    builtFromMapping.Add(item, builtFromList.ToArray());
                    #endregion

                    #region Builds Into
                    List<int> buildsIntoList = new List<int>();
                    foreach (XElement buildsIntoElement in itemElement.Element("builds_into").Elements("item"))
                    {
                        int buildsIntoId = int.Parse(buildsIntoElement.Attribute("id").Value);
                        if (!buildsIntoList.Contains(buildsIntoId))
                        {
                            buildsIntoList.Add(buildsIntoId);
                        }
                    }

                    buildsIntoMapping.Add(item, buildsIntoList.ToArray());
                    #endregion

                    items.Add(item);
                }
            }

            #region Built From
            foreach (Item item in builtFromMapping.Keys)
            {
                List<Item> builtFromItems = new List<Item>();
                foreach (int builtFromId in builtFromMapping[item])
                {
                    Item builtFromItem = items.Where(c => c.ItemId == builtFromId).SingleOrDefault();
                    builtFromItems.Add(builtFromItem);
                }

                item.BuiltFrom = builtFromItems.ToArray();
            }
            #endregion

            #region Builds Into
            foreach (Item item in buildsIntoMapping.Keys)
            {
                List<Item> buildsIntoItems = new List<Item>();
                foreach (int buildsIntoId in buildsIntoMapping[item])
                {
                    Item buildsIntoItem = items.Where(c => c.ItemId == buildsIntoId).SingleOrDefault();
                    buildsIntoItems.Add(buildsIntoItem);
                }

                item.BuildsInto = buildsIntoItems.ToArray();
            }
            #endregion

            SetItemTotals(items);

            items.Sort((x1, x2) => x1.Name.CompareTo(x2.Name));
            _items = new ReadOnlyCollection<Item>(items);

            return _items;
        }

        private static void SetItemTotals(List<Item> items)
        {
            foreach (Item item in items)
            {
                item.Total = -1;
            }

            foreach (Item item in items.Where(c => c.BuiltFrom.Length == 0))
            {
                item.Total = item.Price;
            }

            int iterations = 0;
            while (items.Where(c => c.BuiltFrom.Length > 0 && c.Total == -1).Any() && iterations < 100)
            {
                foreach (Item item in items.Where(c => c.BuiltFrom.Length > 0 && c.Total == -1))
                {
                    int total = 0;
                    bool failed = false;

                    foreach (Item builtFrom in item.BuiltFrom)
                    {
                        if (builtFrom.Total != -1)
                        {
                            total += builtFrom.Total;
                        }
                        else
                        {
                            failed = true;
                            break;
                        }
                    }

                    if (!failed)
                    {
                        item.Total = total;
                    }
                }

                iterations++;
            }
        }
    }
}
